all repos — weimar @ 77821058eddf0c6181cacf983976b6f41e5ee037

Unnamed repository; edit this file 'description' to name the repository.

web/src/routes/image/[id]/+page.svelte (view raw)

  1<script lang="ts">
  2	import { onMount } from 'svelte';
  3	import { getImage, imageDownloadUrl, thumbnailUrl, type Image } from '$lib/api';
  4
  5	let { params } = $props();
  6	let id = $derived(parseInt(params.id));
  7
  8	let img = $state<Image | null>(null);
  9	let loading = $state(true);
 10	let error = $state('');
 11
 12	onMount(async () => {
 13		try {
 14			img = await getImage(id);
 15		} catch (err) {
 16			error = err instanceof Error ? err.message : 'Failed to load image';
 17		} finally {
 18			loading = false;
 19		}
 20	});
 21
 22	function formatSize(bytes: number): string {
 23		if (bytes < 1024) return bytes + ' B';
 24		if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
 25		return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
 26	}
 27
 28	function formatDate(s: string): string {
 29		return new Date(s).toLocaleString();
 30	}
 31</script>
 32
 33{#if loading}
 34	<p>Loading...</p>
 35{:else if error}
 36	<p class="error">{error}</p>
 37{:else if img}
 38	<h1>{img.filename}</h1>
 39
 40	<div class="detail">
 41		<div class="preview">
 42			{#if img.thumbnail_path}
 43				<a href={imageDownloadUrl(img.id)} download={img.filename}>
 44					<img src={thumbnailUrl(img.id)} alt={img.filename} />
 45				</a>
 46			{:else}
 47				<div class="placeholder">No thumbnail</div>
 48			{/if}
 49		</div>
 50
 51		<div class="meta">
 52			<dl>
 53				<dt>Dimensions</dt>
 54				<dd>{img.width} &times; {img.height}</dd>
 55				<dt>File size</dt>
 56				<dd>{formatSize(img.file_size)}</dd>
 57				<dt>Type</dt>
 58				<dd>{img.mime_type}</dd>
 59				<dt>Tags</dt>
 60				<dd>
 61					{#if img.tags.length > 0}
 62						{img.tags.join(', ')}
 63					{:else}
 64						<span class="dim">none</span>
 65					{/if}
 66				</dd>
 67				<dt>Uploaded</dt>
 68				<dd>{formatDate(img.created_at)}</dd>
 69			</dl>
 70
 71			<a href={imageDownloadUrl(img.id)} class="download" download={img.filename}>
 72				Download original
 73			</a>
 74		</div>
 75	</div>
 76
 77	<p class="back"><a href="/browse">&larr; Back to browse</a></p>
 78{/if}
 79
 80<style>
 81	.detail {
 82		display: flex;
 83		gap: 2rem;
 84		margin-top: 1rem;
 85		flex-wrap: wrap;
 86	}
 87	.preview img {
 88		max-width: 100%;
 89		max-height: 60vh;
 90		border-radius: 8px;
 91		box-shadow: 0 2px 8px rgba(0,0,0,0.15);
 92	}
 93	.placeholder {
 94		width: 300px;
 95		height: 200px;
 96		display: flex;
 97		align-items: center;
 98		justify-content: center;
 99		background: #f0f0f0;
100		border-radius: 8px;
101		color: #999;
102	}
103	.meta {
104		min-width: 220px;
105	}
106	dl {
107		margin: 0;
108	}
109	dt {
110		font-weight: 600;
111		margin-top: 0.5rem;
112		font-size: 0.85rem;
113		color: #555;
114	}
115	dd {
116		margin: 0;
117		font-size: 0.95rem;
118	}
119	.dim {
120		color: #999;
121	}
122	.download {
123		display: inline-block;
124		margin-top: 1.5rem;
125		padding: 0.5rem 1.5rem;
126		background: #1a1a2e;
127		color: #eee;
128		text-decoration: none;
129		border-radius: 6px;
130	}
131	.download:hover {
132		background: #16213e;
133	}
134	.back {
135		margin-top: 2rem;
136	}
137	.error {
138		color: #c0392b;
139	}
140</style>